package ws_client

import (
	"encoding/json"
	"github.com/gorilla/websocket"
	"log"
	"net/url"
)

// Client 自定义的websocket服务的客户端接口定义
type Client interface {
	Close() error

	Send(v any) error // kafka通过websocket推送消息给接受者
	Read(v any) error
}

// DefaultClient 客户端接口的一个实现
type DefaultClient struct {
	Host string
	Opt  ClientOptions
	*websocket.Conn
}

func NewClient(host string, fs ...ClientOptionsFunc) *DefaultClient {
	// 得到客户端的配置
	opt := newClientOption(fs...)
	client := DefaultClient{
		Host: host,
		Opt:  opt,
		Conn: nil,
	}

	// 建立websocket客户端与的websocket服务端通信
	conn, err := client.Dial()
	if err != nil {
		panic(err)
	}
	client.Conn = conn
	return &client
}

// Dial 建立websocket客户端与的websocket服务端通信
func (m *DefaultClient) Dial() (*websocket.Conn, error) {
	u := url.URL{Scheme: "ws", Host: m.Host, Path: m.Opt.pattern}
	log.Printf("connecting to %s", u.String())

	conn, _, err := websocket.DefaultDialer.Dial(u.String(), m.Opt.header)
	if err != nil {
		log.Fatal("dial websocket server failed: ", err)
		return nil, err
	}
	return conn, err
}

// Send （kafka）通过websocket客户端发送消息给websocket服务端
func (m *DefaultClient) Send(v any) error {
	// 1. 参数转为json
	data, err := json.Marshal(v)
	if err != nil {
		return err
	}

	// 2. 发送消息（此处的Conn是client的websocket连接）
	err = m.Conn.WriteMessage(websocket.TextMessage, data)
	if err == nil { // 发送成功则不用重连
		return nil
	}

	// todo 发送失败重连
	conn, err := m.Dial()
	if err != nil {
		return err
	}
	m.Conn = conn
	return m.Conn.WriteMessage(websocket.TextMessage, data)
}

func (m *DefaultClient) Read(v any) error {
	_, data, err := m.Conn.ReadMessage()
	if err != nil {
		return err
	}
	// 将内容json解析并绑定到传入参数上
	return json.Unmarshal(data, v)
}
